package com.sxt.demo.djiapplication.exceptionhandler;

import static com.sxt.demo.djiapplication.utils.FileUtil.createFileIfAbsent;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.Process;

import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;

@SuppressWarnings("unused")
public class CrashHandler implements Thread.UncaughtExceptionHandler {

    public static final String TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private final String EXTERNAL_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
    public static final String ERROR_TRACE_PATH = "error_trace";
    public static final String FILE_NAME_SUFFIX = ".trace";
    private static final CrashHandler sInstance = new CrashHandler();
    private Thread.UncaughtExceptionHandler mDefaultCrashHandler;
    private WeakReference<Context> mContext;

    private CrashHandler() {
    }

    public static CrashHandler getInstance() {
        return sInstance;
    }

    public void init(@NonNull Context context) {
        mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
        mContext = new WeakReference<>(context.getApplicationContext());
    }

    /**
     * 当程序中有未被捕获的异常，系统将会调用这个方法
     *
     * @param t 出现未捕获异常的线程
     * @param e 得到异常信息
     */
    @Override
    public void uncaughtException(@NonNull Thread t, @NonNull Throwable e) {
        try {
            //保存到本地
            String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(new Date());
            String fileName = time + FILE_NAME_SUFFIX;
//            exportExceptionToSDCard(e, EXTERNAL_PATH, fileName); // SD卡
            exportExceptionToAppData(
                    e,
                    mContext.get().getFilesDir().getParent()
                            + File.separator + ERROR_TRACE_PATH,
                    fileName
            );
            //下面也可以写上传的服务器的代码
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        e.printStackTrace();
        //如果系统提供了默认的异常处理器，则交给系统去结束程序，否则就自己结束自己
        if (mDefaultCrashHandler != null) {
            mDefaultCrashHandler.uncaughtException(t, e);
        } else {
            Process.killProcess(Process.myPid());
        }
    }

    private void exportExceptionToSDCard(@NonNull Throwable e, String path, String fileName) {
        //判断SD卡是否存在
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            return;
        }
        int permission_write = ContextCompat.checkSelfPermission(mContext.get(),
                Manifest.permission.WRITE_EXTERNAL_STORAGE);
        int permission_read = ContextCompat.checkSelfPermission(mContext.get(),
                Manifest.permission.READ_EXTERNAL_STORAGE);
        if (permission_write != PackageManager.PERMISSION_GRANTED
                || permission_read != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        exportExceptionToPath(e, path, fileName);
    }

    private void exportExceptionToAppData(@NonNull Throwable e, String path, String fileName) {
        exportExceptionToPath(e, path, fileName);
    }

    /**
     * 导出异常信息到指定路径
     *
     * @param e 异常信息
     */
    private void exportExceptionToPath(@NonNull Throwable e, String path, String fileName) {
        File file = new File(path + File.separator + fileName);
        createFileIfAbsent(file);
        try {
            //往文件中写入数据
            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
            pw.println(new SimpleDateFormat(TIME_FORMAT, Locale.CHINA).format(new Date()));
            pw.println(appendPhoneInfo());
            e.printStackTrace(pw);
            pw.close();
        } catch (IOException | PackageManager.NameNotFoundException e1) {
            e1.printStackTrace();
        }
    }

    /**
     * 获取手机信息
     */
    @SuppressLint("ObsoleteSdkInt")
    private String appendPhoneInfo() throws PackageManager.NameNotFoundException {
        PackageManager pm = mContext.get().getPackageManager();
        PackageInfo pi = pm.getPackageInfo(mContext.get().getPackageName(), PackageManager.GET_ACTIVITIES);
        StringBuilder sb = new StringBuilder();
        //App版本
        sb.append("App Version: ");
        sb.append(pi.versionName);
        sb.append("_");
        sb.append(pi.versionCode).append("\n");

        //Android版本号
        sb.append("OS Version: ");
        sb.append(Build.VERSION.RELEASE);
        sb.append("_");
        sb.append(Build.VERSION.SDK_INT).append("\n");

        //手机制造商
        sb.append("Vendor: ");
        sb.append(Build.MANUFACTURER).append("\n");

        //手机型号
        sb.append("Model: ");
        sb.append(Build.MODEL).append("\n");

        //CPU架构
        sb.append("CPU: ");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            sb.append(Arrays.toString(Build.SUPPORTED_ABIS));
        } else {
            //noinspection deprecation
            sb.append(Build.CPU_ABI);
        }
        return sb.toString();
    }
}